﻿using FTBS.Models.Entities;
using FTBS.Models.Entities.Concert;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Net;
using System.Web;

namespace FTBS.Models.BLO
{
    public class HomeBLO
    {
        private TheaterBLO _theaterBlo = new TheaterBLO();
        private FilmBLO _filmBlo = new FilmBLO();

        #region Calculate Distance

        private double deg2rad(double deg)
        {
            return (deg * Math.PI / 180.0);
        }

        private double rad2deg(double rad)
        {
            return (rad / Math.PI * 180.0);
        }

        public TheaterPositionEntity CalculateDistance(string originLat, string originLong, string destLat, string destLong)
        {
            // Calculate distance from origin to destination
            string url = "http://maps.googleapis.com/maps/api/distancematrix/xml?";
            url += "origins=" + originLat + "," + originLong;
            url += "&destinations=" + destLat + "," + destLong;
            url += "&mode=driving";
            url += "&sensor=false";
            return DownloadXML3(url);
        }

        public TheaterPositionEntity DownloadXML3(string url)
        {
            TheaterPositionEntity theaterPosition = new TheaterPositionEntity();

            Stream stream = DownloadResource(url);
            DataSet ds = new DataSet();
            ds.ReadXml(stream);
            theaterPosition.Time = ds.Tables["duration"].Rows[0][1].ToString().Trim().Replace("mins", "phút");
            theaterPosition.Distance = Convert.ToDouble(ds.Tables["distance"].Rows[0][0]);
            theaterPosition.DistanceString = ds.Tables["distance"].Rows[0][1].ToString().Trim();
            ds.Dispose();
            stream.Close();
            stream.Dispose();
            return theaterPosition;
        }

        public static Stream DownloadResource(string url)
        {
            MemoryStream stream = null;

            try
            {
                WebClient client = new WebClient();
                client.Headers.Add("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)");
                byte[] data = client.DownloadData(url);
                stream = new MemoryStream(data);
                client.Dispose();
            }
            catch (WebException ex)
            {
                throw ex;
            }

            return stream;
        }

        public double CalculatePure(double lat1,
                                 double lon1,
                                 double lat2,
                                 double lon2)
        {
            var R = 6371d; // Radius of the earth in km
            var dLat = Deg2Rad(lat2 - lat1);  // deg2rad below
            var dLon = Deg2Rad(lon2 - lon1);
            var a =
              Math.Sin(dLat / 2d) * Math.Sin(dLat / 2d) +
              Math.Cos(Deg2Rad(lat1)) * Math.Cos(Deg2Rad(lat2)) *
              Math.Sin(dLon / 2d) * Math.Sin(dLon / 2d);
            var c = 2d * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1d - a));
            var d = R * c; // Distance in km
            return d;
        }

        public double Deg2Rad(double deg)
        {
            return deg * (Math.PI / 180d);
        }

        public bool IsAroundOneKm(double sLatitude, double sLongitude, double eLatitude,
                               double eLongitude)
        {
            var distance = CalculatePure(sLatitude, sLongitude, eLatitude, eLongitude);
            if (distance <= 1)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        #endregion

        /// <summary>
        /// Convert Theater object to TheaterConcertEntity object
        /// </summary>
        /// <param name="theater"></param>
        /// <returns></returns>
        private TheaterConcertEntity ConvertObjectTheater(Theater theater)
        {
            TheaterConcertEntity result = new TheaterConcertEntity();
            result.TheaterId = theater.TheaterId;
            result.TheaterName = theater.TheaterName;
            result.Address = theater.Address;
            result.PhoneNumber = theater.PhoneNumber;
            result.UserName = theater.UserName;
            result.IsDeleted = theater.IsDeleted;
            result.Latitude = theater.Latitude;
            result.Longitude = theater.Longitude;
            result.ImageURL = theater.ImageURL;
            return result;
        }

        /// <summary>
        /// Get list Theater nearest
        /// </summary>
        /// <param name="customerLat"></param>
        /// <param name="customerLong"></param>
        /// <returns>List of TheaterConcertEntity</returns>
        /// <author>VuongVT</author>
        public List<TheaterConcertEntity> GetListNearestTheater(string customerLat, string customerLong)
        {
            List<TheaterConcertEntity> lstTheaterResult = new List<TheaterConcertEntity>();
            List<Theater> lstAllTheater = new List<Theater>();
            lstAllTheater = _theaterBlo.GetAllTheaterInfo();
            List<TheaterPositionEntity> listPosition = new List<TheaterPositionEntity>();
            foreach (var item in lstAllTheater)
            {
                TheaterPositionEntity theaterPostion = new TheaterPositionEntity();
                theaterPostion = CalculateDistance(customerLat, customerLong, item.Latitude, item.Longitude);
                theaterPostion.TheaterId = item.TheaterId;
                listPosition.Add(theaterPostion);
            }

            //Sort list to select 3 first item
            listPosition = listPosition.OrderBy(rs => rs.Distance).ToList();

            //If list of position has more than 3, select 3 first item
            if (listPosition.Count() > 3)
            {
                for (int i = 0; i < 3; i++)
                {
                    var theaterResult = (from t in lstAllTheater
                                         where t.TheaterId == listPosition[i].TheaterId
                                         select t).FirstOrDefault();
                    TheaterConcertEntity theaterConcertEnt = new TheaterConcertEntity();
                    theaterConcertEnt = ConvertObjectTheater(theaterResult);
                    theaterConcertEnt.Time = listPosition[i].Time;
                    theaterConcertEnt.Distance = listPosition[i].Distance;
                    theaterConcertEnt.DistanceString = listPosition[i].DistanceString;
                    lstTheaterResult.Add(theaterConcertEnt);
                }
            }
            else
            {
                foreach (var item in listPosition)
                {
                     var theaterResult = (from t in lstAllTheater
                                         where t.TheaterId == item.TheaterId
                                         select t).FirstOrDefault();
                     TheaterConcertEntity theaterConcertEnt = new TheaterConcertEntity();
                     theaterConcertEnt = ConvertObjectTheater(theaterResult);
                     theaterConcertEnt.Time = item.Time;
                     theaterConcertEnt.Distance = item.Distance;
                     theaterConcertEnt.DistanceString = item.DistanceString;
                     lstTheaterResult.Add(theaterConcertEnt);
                }
            }
            return lstTheaterResult;
        }

        /// <summary>
        /// Get list Film suggest for Guest
        /// </summary>
        /// <param name="listLocalStorage"></param>
        /// <returns>List of Film</returns>
        /// <author>VuongVT</author>
        public List<Film> GetListFilmSuggestionForGuest(List<LocalStorageConcertEntity> listLocalStorage)
        {
            List<Film> listFilmSuggest = new List<Film>();
            listFilmSuggest = _filmBlo.GetListFilmSuggestionForGuest(listLocalStorage);
            return listFilmSuggest;
        }

        /// <summary>
        /// Get list Film suggest for Customer
        /// </summary>
        /// <param name="listLocalStorage"></param>
        /// <returns>List of Film</returns>
        /// <author>VuongVT</author>
        public List<Film> GetListFilmSuggestionForCustomer(List<LocalStorageConcertEntity> listLocalStorage, string userName)
        {
            List<Film> listFilmSuggest = new List<Film>();
            listFilmSuggest = _filmBlo.GetListFilmSuggestionForCustomer(listLocalStorage, userName);
            return listFilmSuggest;
        }

        /// <summary>
        /// Get list localStorage result and process string
        /// </summary>
        /// <param name="localStorageResult">string value of localStorage</param>
        /// <returns>List of LocalStorageConcertEntity</returns>
        /// <author>VuongVT</author>
        public List<LocalStorageConcertEntity> GetListViewResultCategory(string localStorageResult)
        {
            List<LocalStorageConcertEntity> listLocalStorage = new List<LocalStorageConcertEntity>();
            if (!localStorageResult.Equals("null"))
            {
                var strFirst = localStorageResult.Replace('[', ' ');
                var strSecond = strFirst.Replace('{', ' ');
                var strThirst = strSecond.Replace('\"', ' ');
                var strFour = strThirst.Replace('}', ' ');
                var strFive = strFour.Replace(']', ' ');
                var strFinal = strFive.Trim();
                var resultSplit = strFinal.Split(',');
                for (int i = 0; i < resultSplit.Count(); i++)
                {
                    if (i % 2 == 0)
                    {
                        LocalStorageConcertEntity localStorage = new LocalStorageConcertEntity();
                        var resultItemId = resultSplit[i].Split(':');
                        localStorage.CategoryId = Convert.ToInt32(resultItemId[1].Trim().ToString());
                        var resultItemView = resultSplit[i + 1].Split(':');
                        localStorage.ViewTime = Convert.ToInt32(resultItemView[1].Trim().ToString());
                        listLocalStorage.Add(localStorage);
                        i = i + 1;
                    }
                }
                return listLocalStorage.OrderByDescending(lc => lc.ViewTime).ToList();
            }
            else
            {
                return listLocalStorage;
            }
        }

        public List<string> GetLatitudeAndLongitude(string localStorageValue)
        {
            List<string> listResult = new List<string>();
            if (!localStorageValue.Equals("null"))
            {
                var strFirst = localStorageValue.Replace('[', ' ');
                var strSecond = strFirst.Replace('{', ' ');
                var strThirst = strSecond.Replace('\"', ' ');
                var strFour = strThirst.Replace('}', ' ');
                var strFive = strFour.Replace(']', ' ');
                var strFinal = strFive.Trim();
                var resultSplit = strFinal.Split(',');
                for (int i = 0; i < resultSplit.Count(); i++)
                {
                    var resultItem = resultSplit[i].Split(':');
                    listResult.Add(resultItem[1]);
                }
            }
            return listResult;
        }

        public List<TheaterConcertEntity> GetListTheaterPosition(string listTheaterLocalStorage)
        {
            List<TheaterConcertEntity> listTheater = new List<TheaterConcertEntity>();
            if (!listTheaterLocalStorage.Equals("null"))
            {
                var strFirst = listTheaterLocalStorage.Replace('[', ' ');
                var strSecond = strFirst.Replace('{', ' ');
                var strThirst = strSecond.Replace('\"', ' ');
                var strFour = strThirst.Replace('}', ' ');
                var strFive = strFour.Replace(']', ' ');
                var strFinal = strFive.Trim();
                var resultSplit = strFinal.Split(',');
                for (int i = 0; i < resultSplit.Count() - 1; i++)
                {
                    TheaterConcertEntity theaterPosition = new TheaterConcertEntity();
                    if (i % 2 == 0)
                    {
                        var resultItem = resultSplit[i].Split(':');
                        theaterPosition.TheaterId = Convert.ToInt32(resultItem[1]);
                        Theater theater = new Theater();
                        theater = _theaterBlo.GetTheaterById(theaterPosition.TheaterId);
                        theaterPosition.Address = theater.Address;
                        theaterPosition.ImageURL = theater.ImageURL;
                        theaterPosition.TheaterName = theater.TheaterName;

                        var resultItemTimeAndDistance = resultSplit[i+1].Split(':');
                        string totalTimeAndKm = resultItemTimeAndDistance[1];
                        string temp = totalTimeAndKm;
                        int indexOfAddCharacter = totalTimeAndKm.IndexOf('+');
                        string time = totalTimeAndKm.Substring(0, indexOfAddCharacter);
                        string distance = temp.Substring(indexOfAddCharacter+1);
                        var indexOfUndefine = distance.IndexOf('u');
                        distance = distance.Remove(indexOfUndefine);
                        theaterPosition.Time = time;
                        theaterPosition.DistanceString = distance;
                        
                        i = i + 1;
                    }
                    
                    
                    //theaterPosition.Time = resultItem[1];
                    listTheater.Add(theaterPosition);
                }
            }
            return listTheater;
        }

        /// <summary>
        /// Check film wants to add exist in List or not
        /// </summary>
        /// <param name="listFilm"></param>
        /// <param name="film"></param>
        /// <returns>True: Exist -- False: Not Exist</returns>
        public bool IsFilmExistInList(List<FilmConcertEntity> listFilm, Film film)
        {
            foreach (var item in listFilm)
            {
                if (item.FilmId == film.FilmId)
                {
                    return true;
                }
            }
            return false;
        }
   
    }
}